package yartiss.gui.view;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.BoundedRangeModel;
import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.filechooser.FileFilter;

import net.miginfocom.swing.MigLayout;
import yartiss.framework.view.AbstractView;
import yartiss.framework.viewmodel.AbstractViewModel;
import yartiss.gui.graphics.JChartPane;
import yartiss.gui.graphics.rendrerers.BarChartRenderer;
import yartiss.gui.graphics.rendrerers.LineChartRenderer;
import yartiss.service.model.IChartModel;
import yartiss.service.model.Metric;
import yartiss.service.model.PoliciesTableModel;
import yartiss.service.model.Scenario;
import yartiss.service.model.ScenariosTableModel;
import yartiss.service.viewmodel.BenchmarkViewModel;


@SuppressWarnings("serial")
public class BenchmarkView extends AbstractView {

	public AbstractViewModel viewModel; 
	public JButton startSimulation;
	public JButton load;

	public JTextField durationField;
	private IChartModel<Scenario> scenariosModel;
	private IChartModel<Metric> metricsModel;
	private JChartPane<Scenario> scenarioschart;
	private JChartPane<Metric> metricsChart;
	private JProgressBar globalProgressBar;
	private JButton addScenario;
	private JButton removeScenario;
	private JTable scenariosTable;
	private JButton addPolicy;
	private JButton removePolicy;
	private JTable policiesTable;
	private PoliciesTableModel policiesModel;
	private ScenariosTableModel scenariosTableModel;
	private BoundedRangeModel globalProgressModel;
	private JComboBox<String> policyNameEditor;
	private JComboBox<String> consProfileNameEditor;
	public JCheckBox debugCheckBox;

	public ActionListener startSimulationCommand = null;
	public ActionListener loadCommand = null;
	public ActionListener saveCommand = null;
	public JTextField nbProcField;
	public JTextField systemsFileField;
	private JButton browseFileButton;

	public BenchmarkView(){
		setResizeWeight(1.0);
		setOneTouchExpandable(true);
		setLeftComponent(buildLeftComponent());
		setRightComponent(buildRightComponent());
		registerGUIListerners();
		initializeGUI();
	}

	private void initializeGUI() {
		// TODO Auto-generated method stub
	}

	private void registerGUIListerners() {
		addPolicy.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				policiesModel.addPolicy(policiesModel.getAvailablePolicies()[0], "");
			}
		});
		removePolicy.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				int selectedRow = policiesTable.getSelectedRow();
				if(selectedRow >= 0)
					policiesModel.removeRow(selectedRow);
			}
		});

		addScenario.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				scenariosTableModel.addRow();
			}
		});
		removeScenario.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				int selectedRow = scenariosTable.getSelectedRow();
				if(selectedRow >= 0)
					scenariosTableModel.removeRow(selectedRow);
			}
		});

		browseFileButton.addActionListener( new ActionListener() {
			@Override	public void actionPerformed(ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser(systemsFileField.getText());
				fileChooser.setFileFilter(new FileFilter() {
					@Override
					public String getDescription() {
						return "RTSS";
					}

					@Override
					public boolean accept(File f) {
						return true;
					}
				});
				int result = fileChooser.showOpenDialog(browseFileButton);
				if (result == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					viewModel.setProperty("SystemsFile",file.getPath());
					setProperty("SystemsFile",file.getPath());
				}
			}
		});
		debugCheckBox.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				viewModel.setProperty("Debug", debugCheckBox.isSelected());
				startSimulation.setEnabled(true);
				scenarioschart.setDebug(debugCheckBox.isSelected());
			}
		});

		addListeners(durationField,"Duration");
		addListeners(nbProcField,"NbProc");
	}

	public class MyActionListerner implements ActionListener, FocusListener, KeyListener{

		private final String propName;
		String oldValue;
		private final JTextField source;
		private boolean valide;
		public MyActionListerner(JTextField source, String propName){
			this.source = source;
			this.propName = propName;
		}
		@Override public void actionPerformed(ActionEvent e) {doIt(e.getSource());}
		@Override public void focusGained(FocusEvent e) {oldValue = source != null ? source.getText() : "";}
		@Override public void focusLost(FocusEvent e) {doIt(e.getSource());}
		private void doIt(Object source){
			Object value = null;
			if(this.source != null && !valide){
				this.source.setText(oldValue);
				this.source.setForeground(Color.BLACK);
			}
			value = getProperty(propName);
			fireGuiPropertyChanged(propName, value, value);
		}
		@Override
		public void keyTyped(KeyEvent e) {
			String input = source.getText();
			Pattern p = Pattern.compile("[A-Z,a-z,&%$#@!()*^]");
			Matcher m = p.matcher(input);
			if (m.find()){
				source.setForeground(Color.RED);
				valide = false;
			}
			else {
				source.setForeground(Color.black);
				valide = true;
			}
		}
		@Override public void keyPressed(KeyEvent e) {}
		@Override public void keyReleased(KeyEvent e) {}
	}

	private void addListeners(JTextField f, String prop){
		MyActionListerner l = new MyActionListerner(f, prop);
		f.addActionListener(l);
		f.addFocusListener(l);
		f.addKeyListener(l);
	}

	private JComponent buildRightComponent() {
		JPanel simulationPane = new JPanel();
		BoxLayout b = new BoxLayout(simulationPane, BoxLayout.Y_AXIS);
		simulationPane.setLayout(b);
		simulationPane.setBorder(BorderFactory.createTitledBorder("Simulation"));

		globalProgressBar = new JProgressBar();

		startSimulation = new JButton("Go");
		load = new JButton("load");
		durationField = new JTextField(15); 
		nbProcField = new JTextField(15); 
		systemsFileField = new JTextField(15); 
		systemsFileField.setMinimumSize(new Dimension(80,10));
		browseFileButton = new JButton("browse");
		debugCheckBox = new JCheckBox("Debug");

		JPanel p = new JPanel(new MigLayout());
		p.add(globalProgressBar    , "span, growx, wrap para");
		p.add(startSimulation, "gap para");
		p.add(load, "gap para");
		//p.add(screenShot, "gap para");
		p.add(new JLabel("Duratiobn"), "gap para");p.add(durationField    , "span, growx, wrap para");
		p.add(new JLabel("Systems file"), "gap para");p.add(systemsFileField    ,  "gap para");
		p.add(browseFileButton    ,   "span, growx, wrap para");
		p.add(new JLabel("Nb Proc"), "gap para");p.add(nbProcField );
		p.add(debugCheckBox );
		simulationPane.add(p,"growx, wrap, gaptop 10");

		p = new JPanel(new MigLayout());


		JPanel scenariosPane = new JPanel(new MigLayout());
		scenariosPane.setBorder(BorderFactory.createTitledBorder("Scenarios"));
		addScenario 	= new JButton("add");
		removeScenario 	= new JButton("remove");
		scenariosPane.add(addScenario    );
		scenariosPane.add(removeScenario  , "span, growx, wrap para" );
		scenariosTable = new JTable();

		consProfileNameEditor = new JComboBox<String>();

		JScrollPane sp = new JScrollPane(scenariosTable);
		sp.setMinimumSize(new Dimension(50,70));
		scenariosPane.add(sp,"span, growx, wrap para");




		JPanel policiesPane = new JPanel(new MigLayout());
		policiesPane.setBorder(BorderFactory.createTitledBorder("Scheduling Policies"));
		addPolicy	= new JButton("add");
		removePolicy 	= new JButton("remove");
		policiesPane.add(addPolicy    );
		policiesPane.add(removePolicy  , "span, growx, wrap para" );
		policiesTable = new JTable();
		policyNameEditor= new JComboBox<String>(new String []{"a","b"});


		JScrollPane sp2 = new JScrollPane(policiesTable);
		sp2.setMinimumSize(new Dimension(50,70));
		policiesPane.add(sp2,"span, growx, wrap para");



		JPanel rightPane = new JPanel();
		BoxLayout layout = new BoxLayout(rightPane, BoxLayout.Y_AXIS);
		rightPane.setLayout(layout);
		rightPane.add(simulationPane);
		rightPane.add(scenariosPane);
		rightPane.add(policiesPane);

		JPanel pp = new JPanel(new LayoutManager() {
			int width=330;
			@Override public void removeLayoutComponent(Component comp) {}

			@Override public Dimension preferredLayoutSize(Container parent) {
				return new Dimension(width,parent.getHeight());
			}

			@Override public Dimension minimumLayoutSize(Container parent) {
				return new Dimension(width,parent.getHeight());
			}

			@Override public void layoutContainer(Container parent) {
				for (Component comp : parent.getComponents()) {
					comp.setSize(width, parent.getHeight());
				}
			}
			@Override public void addLayoutComponent(String name, Component comp) {}
		});
		pp.add(rightPane);

		JScrollPane Scroll = new JScrollPane(pp);
		Scroll.setMinimumSize(new Dimension(340,0));
		Scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		return Scroll;
	}

	private JComponent buildLeftComponent() {
		JTabbedPane tabbedPane = new JTabbedPane();
		scenarioschart = new JChartPane<Scenario>(null);
		scenarioschart.setChartRenderer(new BarChartRenderer());

		metricsChart = new JChartPane<Metric>(null);
		metricsChart.setChartRenderer(new LineChartRenderer());

		tabbedPane.addTab("Scenarios", scenarioschart);
		tabbedPane.addTab("Metrics", metricsChart);

		return tabbedPane;
	}

	@Override
	public AbstractViewModel getDataContext() {
		return viewModel;
	}


	private PropertyChangeListener listener = new PropertyChangeListener() {
		@Override  public void propertyChange(PropertyChangeEvent evt) {
			setProperty(evt.getPropertyName());
		}
	};
	@Override
	public void setDataContext(AbstractViewModel viewModel) {
		unSuscribeListeners();
		this.viewModel = viewModel;
		suscribeListeners();
		fireViewModelChanged(viewModel);

	}

	private void suscribeListeners() {
		if(viewModel != null)
			viewModel.registerPropertyChangeListerner(listener);
	}

	private void unSuscribeListeners() {
		if(viewModel != null)
			viewModel.unregisterPropertyChangeListener(listener);
	}

	private void setProperty(String propName){
		Object value = viewModel.getProperty(propName);

		if("ScenariosModel".equals(propName)){
			scenariosModel = viewModel.getProperty(propName);
			scenarioschart.setModel(scenariosModel);
		}
		else if("MetricsModel".equals(propName)){	
			metricsModel = viewModel.getProperty(propName);
			metricsChart.setModel(metricsModel);
		}
		else if("PoliciesModel".equals(propName)){
			policiesModel = viewModel.getProperty(propName);
			policyNameEditor.setModel(new DefaultComboBoxModel<String>(policiesModel.getAvailablePolicies()));
			policiesTable.setModel(policiesModel);
			policiesTable.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(policyNameEditor));
			policiesModel.addTableModelListener(new TableModelListener() {
				@Override public void tableChanged(TableModelEvent e) {
					startSimulation.setEnabled(true);
					if(policiesModel.getRowCount() <= 0)
						removePolicy.setEnabled(false);
					else 
						removePolicy.setEnabled(true);
				}
			});
		}
		else if("ScenariosTableModel".equals(propName)){
			scenariosTableModel = viewModel.getProperty(propName);
			consProfileNameEditor.setModel(new DefaultComboBoxModel<String>(scenariosTableModel.getAvailableConsProfiles()));
			scenariosTable.setModel(scenariosTableModel);
			scenariosTable.getColumnModel().getColumn(5).setCellEditor(new DefaultCellEditor(consProfileNameEditor));
			scenariosTableModel.addTableModelListener(new TableModelListener() {
				@Override public void tableChanged(TableModelEvent e) {
					startSimulation.setEnabled(true);
					if(scenariosTableModel.getRowCount() <= 0)
						removeScenario.setEnabled(false);
					else 
						removeScenario.setEnabled(true);
				}
			});
		}
		else if("GlobalProgressModel".equals(propName)){
			globalProgressModel = viewModel.getProperty(propName);
			globalProgressBar.setModel(globalProgressModel);
		}
		else if("StartSimulationCommand".equals(propName)){
			startSimulation.removeActionListener(startSimulationCommand);
			startSimulationCommand = viewModel.getProperty(propName);
			startSimulation.addActionListener(startSimulationCommand);
		}
		else if("IsContentChanged".equals(propName)){
			Boolean enabled = viewModel.getProperty(propName);
			startSimulation.setEnabled(enabled);
		}
		else if("Debug".equals(propName)){
			boolean debug = viewModel.getProperty(propName);
			debugCheckBox.setSelected(debug);
			scenarioschart.setDebug(debugCheckBox.isSelected());
		}
		else{
			setProperty(propName, value);
		}
	}

	private void fireViewModelChanged(AbstractViewModel vm){
		for (String propName : propertiesNames) {
			setProperty(propName);
		}
		setProperty("ScenariosModel");
		setProperty("MetricsModel");
		setProperty("PoliciesModel");
		setProperty("ScenariosTableModel");
		setProperty("GlobalProgressModel");
		setProperty("StartSimulationCommand");
		setProperty("Debug");
	}

	public static void main(String[] args) {

		JFrame window = new JFrame("RTSS-");
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension d = new Dimension(screenSize);
		d.width  *= (5.0 / 6.0);
		d.height *= (5.0 / 6.0);
		window.setBounds((screenSize.width - d.width) / 2, (screenSize.height - d.height) / 2, d.width, d.height);
		window.setPreferredSize(d);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		BenchmarkViewModel vm = new BenchmarkViewModel();
		BenchmarkView view = new BenchmarkView();

		vm.setView(view);
		JComponent root = (JComponent) vm.getView();

		window.setContentPane(root);
		window.setVisible(true);
	}

}
